/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cz.hamacekj.geometr.internalplugins;

import cz.hamacekj.geometr.CircleObject;
import cz.hamacekj.geometr.plugin.ConstructionObject;
import cz.hamacekj.geometr.plugin.ConstructionPlugin;
import cz.hamacekj.geometr.plugin.ICircleObject;
import cz.hamacekj.geometr.plugin.IPoint;
import cz.hamacekj.geometr.plugin.IPointObject;
import cz.hamacekj.geometr.plugin.IToolBox;
import cz.hamacekj.geometr.plugin.InputParameters;
import cz.hamacekj.geometr.plugin.InputParametersInterface;
import cz.hamacekj.geometr.plugin.ParameterItem;
import cz.hamacekj.geometr.plugin.ParameterObject;
import cz.hamacekj.geometr.plugin.ParameterString;
import cz.hamacekj.geometr.plugin.ParameterValue;
import cz.hamacekj.geometr.plugin.PrimitiveObject;
import cz.hamacekj.geometr.plugin.ValueArgument;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import javax.swing.ImageIcon;

/**
 * Plugin pro vytvoření bodu.
 * @author hamacekh
 */
public class PointPlugin implements ConstructionPlugin {

    protected IToolBox toolbox;
    protected String error;

    public PointPlugin() {
    }

    
    public PointPlugin(IToolBox toolbox) {
        this.toolbox = toolbox;
    }
    

    public void setToolbox(IToolBox toolbox){
        this.toolbox = toolbox;
    }
    
    @Override
    public String getPluginName() {
        return "Bod";
    }

    @Override
    public InputParametersInterface[] getPossibleParameters() {
        InputParametersInterface twoObjects = new TwoObjectParameters();
        InputParametersInterface pointDistanceParameters = new PointDistanceParameters();
        InputParametersInterface firstPoint = new FirstPointParameters();
        InputParametersInterface[] res = {twoObjects, pointDistanceParameters, firstPoint
        , new CirclePoint()};
        return res;
    }

    @Override
    public ImageIcon getIcon() {
        return null;
    }

    @Override
    public ConstructionObject[] createConstructionObject(InputParametersInterface parametersType, ConstructionObject[] objects, ValueArgument[] values) {
        if(parametersType instanceof TwoObjectParameters){
            final Set<? extends PrimitiveObject> intersection = toolbox.intersect(objects[0],objects[1]);
            final String fName = objects[0].getLabel();
            final String sName = objects[1].getLabel();
            final String name = values[0].getRealInput();
            if(!name.matches("^[A-Z][0-9]*$")){
                this.error = "Neplatný název bodu.";
                return null;
            }
            ArrayList<ConstructionObject> res = new ArrayList<>();
            int i = 0;
            for(final PrimitiveObject p: intersection){
                final int j = ++i;
                final Set<PrimitiveObject> pset = new HashSet<>();
                final String fullName;
                if (intersection.size() > 1){
                    fullName = name+(new Integer(j)).toString();
                }else{
                    fullName = name;
                }
                pset.add(p);
                res.add(new ConstructionObject() {

                    @Override
                    public String getLabel() {
                        return fullName;
                    }

                    @Override
                    public boolean isLabelShown() {
                        return true;
                    }

                    @Override
                    public Set<PrimitiveObject> getPrimitiveObjects() {
                        return pset;
                    }

                    @Override
                    public String getStepDescription() {
                        return name+", "+name+" <\\in> "+fName+" <\\intersection> "+sName;
                    }
                });
            }
            return res.toArray(new ConstructionObject[0]);
        }
        if(parametersType instanceof PointDistanceParameters){
            final String name = values[0].getRealInput();
            if(!name.matches("^[A-Z][0-9]*$")){
                this.error = "Neplatný název bodu.";
                return null;
            }
            ConstructionObject object = objects[0];
            final String objectName = object.getLabel();
            IPointObject point = (IPointObject)objects[1].getPrimitiveObjects().iterator().next();
            final String pointName = objects[1].getLabel();
            final double distance = values[1].getValue();
            if(Double.isNaN(distance) || distance < 0.0001){
                this.error = "Zadaná hodnota do pole "+values[1].getArgumentName()
                        +" není hodnotou vzdálenosti. Nemůžu vytvořit objekt.";
                return null;
            }
            ICircleObject circle = toolbox.createCircleObject(point.getPoint(), distance);
            Set<PrimitiveObject> circleSet = new HashSet<>();
            circleSet.add(circle);
            ArrayList<Set<? extends PrimitiveObject>> list = new ArrayList<>();
            list.add(circleSet);
            list.add(object.getPrimitiveObjects());
            final Collection<? extends PrimitiveObject> result = toolbox.intersect(list);
            if(result == null || result.isEmpty()){
                this.error = "Nenalezen žádný bod na zadaném objektu v určené vzdálenosti od bodu.";
                return null;
            }
            ArrayList<ConstructionObject> constructionObjects = new ArrayList<>(result.size());
            int i = 0;
            for(final PrimitiveObject p : result){
                i++;
                final String label = result.size() == 1 ? name : name+i;
                if(p instanceof IPointObject){
                    final Set<PrimitiveObject> objSet = new HashSet<>();
                    objSet.add(p);
                    constructionObjects.add(new ConstructionObject() {

                        @Override
                        public String getLabel() {
                            return label;
                        }

                        @Override
                        public boolean isLabelShown() {
                            return true;
                        }

                        @Override
                        public Set<PrimitiveObject> getPrimitiveObjects() {
                            return objSet;
                        }

                        @Override
                        public String getStepDescription() {
                            return name+", "+name+" <\\in> "+objectName+" <\\and> |"+pointName+name+"| = "+distance;
                        }
                    });
                    
                }
            }
            return constructionObjects.toArray(new ConstructionObject[1]);
        }
        
        if(parametersType instanceof FirstPointParameters){
            final String name = values[0].getRealInput();
            if(!name.matches("^[A-Z][0-9]*$")){
                this.error = "Neplatný název bodu.";
                return null;
            }
            final Set<PrimitiveObject> set = new HashSet<>();
            set.add(toolbox.createPointObject(0, 0));
            ConstructionObject point = new ConstructionObject() {

                @Override
                public String getLabel() {
                    return name;
                }

                @Override
                public boolean isLabelShown() {
                    return true;
                }

                @Override
                public Set<PrimitiveObject> getPrimitiveObjects() {
                    return set;
                }

                @Override
                public String getStepDescription() {
                    return name;
                }
            };
            ConstructionObject[] result = { point };
            return result;
        }
        if(parametersType instanceof CirclePoint){
            final String name = values[0].getRealInput();
            if(!name.matches("^[A-Z][0-9]*$")){
                this.error = "Neplatný název bodu.";
                return null;
            }
            ConstructionObject circle = objects[0];
            final String circleName = circle.getLabel();
            PrimitiveObject po = circle.getPrimitiveObjects().iterator().next();
            CircleObject primCircle;
            if(!(po instanceof CircleObject)){
                this.error = "Zadaný objekt není kružnice.";
                return null;
            }
            primCircle = (CircleObject)po;
            IPoint center = primCircle.getCenter();
            IPoint newPoint = toolbox.createPoint(center.getX() + primCircle.getRadius()
                    , center.getY());
            IPointObject pointObject = toolbox.createPointObject(newPoint);
            Set<PrimitiveObject> set = new HashSet<>();
            set.add(pointObject);
            ConstructionObject ro = toolbox.createConstructionObject(name, true, set,
                    name+", "+name+" <\\in> "+circleName);
            ConstructionObject[] res = { ro };
            return res;
        }
        return null;
    }
    
    @Override
    public String getError(){
        String error = this.error;
        this.error = null;
        return error;
    }
    
    private class TwoObjectParameters extends InputParameters {

        @Override
        public String getParametersCaption() {
            return "Průnik dvou objektů";
        }

        @Override
        public ParameterItem[] getParameters() {
            ParameterItem[] res = new ParameterItem[5];
            res[0] = new ParameterString() {

                @Override
                public String getText() {
                    return "Název průniku:";
                }
            };
            res[1] = new ParameterValue() {

                @Override
                public String getCaption() {
                    return "Název";
                }
            };
            res[2] = new ParameterString() {

                @Override
                public String getText() {
                    return "Objekty k průniku:";
                }
            };
            
            res[3] = new ParameterObject() {

                @Override
                public String getCaption() {
                    return "1. objekt";
                }

                @Override
                public String[] getObjectNames() {
                    return null;
                }
            };
            res[4] = new ParameterObject() {

                @Override
                public String getCaption() {
                    return "2. objekt";
                }

                @Override
                public String[] getObjectNames() {
                    return null;
                }
            };
            return res;
        }
        
    }
    
    private class PointDistanceParameters extends InputParameters{

        @Override
        public String getParametersCaption() {
            return "Objekt a vzdálenost od bodu";
        }

        @Override
        public ParameterItem[] getParameters() {
            ParameterItem[] res = new ParameterItem[7];
            res[0] = new ParameterString() {

                @Override
                public String getText() {
                    return "Název";
                }
            };
            res[1] = new ParameterValue() {

                @Override
                public String getCaption() {
                    return "Název bodu";
                }
            };
            res[2] = new ParameterString() {

                @Override
                public String getText() {
                    return "Objekt na kterém leží";
                }
            };
            res[3] = new ParameterObject() {

                @Override
                public String getCaption() {
                    return "Objekt";
                }

                @Override
                public String[] getObjectNames() {
                    String[] res = {"Úsečka", "Přímka", "Polopřímka"};
                    return res;
                }
            };
            res[4] = new ParameterString() {

                @Override
                public String getText() {
                    return "Vzdálenost od bodu";
                }
            };
            res[5] = new ParameterObject() {

                @Override
                public String getCaption() {
                    return "Bod";
                }

                @Override
                public String[] getObjectNames() {
                    String[] res = {"Bod"};
                    return res;
                }
            };
            res[6] = new ParameterValue() {

                @Override
                public String getCaption() {
                    return "Vzdálenost";
                }
            };
            return res;
        }

        @Override
        public String getHelp() {
            return "<h1>Vzdálenost od bodu</h1>"
                    + "<p>"
                    + "Tato možnost vytvoří bod, pojmenuje ho podle prvního parametru <b>Název</b>. "
                    + "Bod bude ležet na objektu zadaném v druhém parametru a bude ve vzdálenosti zadané třetím "
                    + "parametrem od bodu zadaného čtvrtým parametrem."
                    + "</p>"
                    + "<p>"
                    + "Typické použití: chci vytvořit bod A, ležící na přímce XY ve vzdálenosti 3 od bodu X."
                    + "</p>";
        }
        
        
        
    }
    
    private class FirstPointParameters extends InputParameters {

        @Override
        public String getParametersCaption() {
            return "První bod";
        }

        @Override
        public ParameterItem[] getParameters() {
            ParameterItem[] res = new ParameterItem[1];
            res[0] = new ParameterValue() {

                @Override
                public String getCaption() {
                    return "Název";
                }
            };
            return res;
        }

        @Override
        public int getMaxStepsToShow() {
            return 0;
        }

        @Override
        public int getMinStepsToShow() {
            return 0;
        }
        
    }
    
    private class CirclePoint extends InputParameters{

        @Override
        public String getParametersCaption() {
            return "Bod na kružnici";
        }

        @Override
        public ParameterItem[] getParameters() {
            ParameterItem[] res = new ParameterItem[4];
            res[0] = new ParameterString() {

                @Override
                public String getText() {
                    return "Název";
                }
            };
            res[1] = new ParameterValue() {

                @Override
                public String getCaption() {
                    return "Název";
                }
            };
            res[2] = new ParameterString() {

                @Override
                public String getText() {
                    return "Na kružnici:";
                }
            };
            res[3] = new ParameterObject() {

                @Override
                public String getCaption() {
                    return "Kružnice";
                }

                @Override
                public String[] getObjectNames() {
                    String[] res = { "Kružnice" };
                    return res;
                }
            };
            return res;
        }

        @Override
        public String getHelp() {
            return "<h1>Vytvoření bodu na kružnici</h1>"
                    + "<p>Touto možností můžete vytvořit bod na kružnici."
                    + " Seznam parametrů:</p>"
                    + "<ul>"
                    + "<li> <b>Název</b> - název nového bodu"
                    + "<li> <b>Kružnice</b> - název kružnice na které se má bod objevit"
                    + "</ul>"
                    + "<p>Tento objekt lze vytvořit nejdříve v druhém kroku (v prvním"
                    + " ještě jistě nebude nakreslená kružnice). Nejpozději "
                    + "však ve třetím kroku. Bod na kružnici by měl sloužit jako"
                    + "jeden z výchozích objektů na nákresu a ne jako berlička "
                    + "při samotném rýsování.</p>";
        }

        @Override
        public int getMaxStepsToShow() {
            return 2;
        }

        @Override
        public int getMinStepsToShow() {
            return 1;
        }
        
        
        
        
    
    }
    
}
